﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;

namespace Lab01Client
{
    class Program
    {
        protected IPAddress _server_address;
        protected int _server_port;
        protected HashSet<int> _request_ids;
        public Program(IPAddress address,int port)
        {
            _server_address = address;
            _server_port = port;
            _request_ids = new HashSet<int>();

        }

        public void Start()
        {
            try
            {
                int command = 0;
                HashSet<int> requests = new HashSet<int>();


                do
                {
                    Console.WriteLine("Menu");
                    Console.WriteLine("1 - Exit");
                    Console.WriteLine("2 - Add Array");
                    Console.WriteLine("3 - Show Servers Array");
                    Console.WriteLine("4 - Process");
                    Console.WriteLine("5 - Show result");

                    command = Int32.Parse(Console.ReadLine());

                    switch (command)
                    {
                        case 2:
                            Console.WriteLine("Enter array size:");
                            int size = Int32.Parse(Console.ReadLine());
                            if (size > 0)
                            {
                                int []array = new int[size];
                                for (int i = 0; i < size; i++)
                                {
                                    Console.Write("Enter element {0}:", i);
                                    array[i] = Int32.Parse(Console.ReadLine());
                                }
                                Console.Write("Sending request to server ...");
                                int rq_index = AddArray(array);
                                Console.WriteLine("{0}", rq_index);
                                requests.Add(rq_index);
                            }
                            break;
                        case 3:
                            {
                                Console.WriteLine("We have following requests:");
                                foreach (int rq_id in requests) Console.Write("{0} ", rq_id);
                                Console.WriteLine();
                                int rq_index = Int32.Parse(Console.ReadLine());
                                int[] array = ShowServerArray(rq_index);
                                foreach (int a in array) Console.Write("{0} ", a);
                                Console.WriteLine();
                            }
                            break;
                        case 4:
                            {
                                Console.WriteLine("We have following requests:");
                                foreach (int rq_id in requests) Console.Write("{0} ", rq_id);
                                Console.WriteLine();
                                int rq_index = Int32.Parse(Console.ReadLine());
                                Process(rq_index);
                                Console.WriteLine("Done");
                            }
                            break;
                        case 5:
                            {
                                Console.WriteLine("We have following requests:");
                                foreach (int rq_id in requests) Console.Write("{0} ", rq_id);
                                Console.WriteLine();
                                int rq_index = Int32.Parse(Console.ReadLine());
                                int[] array = ShowResult(rq_index);
                                foreach (int a in array) Console.Write("{0} ", a);
                                Console.WriteLine();

                            }
                            break;
                    }
                } while (command != 1);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

        }

        public int AddArray(int[] array)
        {
            IPEndPoint end_point = new IPEndPoint(_server_address, _server_port);
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(end_point);
            BinaryFormatter bf = new BinaryFormatter();
            NetworkStream ns = new NetworkStream(socket);
            try { 
            Int32 command = 1; //AddArray
            bf.Serialize(ns,command);
            bf.Serialize(ns, array);
            ns.Flush();
            socket.Shutdown(SocketShutdown.Send);
            Int32 error_code = (Int32)bf.Deserialize(ns);
            if (error_code != 0) throw new Exception("My Custom exception");
            Int32 id = (Int32)bf.Deserialize(ns);
            return id;
            }
            finally
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Disconnect(false);
            }
        }

        public int[] ShowServerArray(int id)
        {
            IPEndPoint end_point = new IPEndPoint(_server_address, _server_port);
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(end_point);
            BinaryFormatter bf = new BinaryFormatter();
            NetworkStream ns = new NetworkStream(socket);
            try { 
            Int32 command = 2; //ShowServerArray
            bf.Serialize(ns, command);
            bf.Serialize(ns, id);
            ns.Flush();
            socket.Shutdown(SocketShutdown.Send);
            Int32 error_code = (Int32)bf.Deserialize(ns);
            if (error_code != 0) throw new Exception("My Custom exception");
            int[] array = (int[])bf.Deserialize(ns);
             return array;
            }
            finally
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Disconnect(false);
            }

        }

        public void Process(int id)
        {
            IPEndPoint end_point = new IPEndPoint(_server_address, _server_port);
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(end_point);
            BinaryFormatter bf = new BinaryFormatter();
            NetworkStream ns = new NetworkStream(socket);
            try { 
            Int32 command = 3; //Process
            bf.Serialize(ns, command);
            bf.Serialize(ns, id);
            ns.Flush();
            socket.Shutdown(SocketShutdown.Send);
            Int32 error_code = (Int32)bf.Deserialize(ns);
            if (error_code != 0) throw new Exception("My Custom exception");
            }
            finally
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Disconnect(false);
            }
            return;
        }

        public int[] ShowResult(int id)
        {
            IPEndPoint end_point = new IPEndPoint(_server_address, _server_port);
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(end_point);
            BinaryFormatter bf = new BinaryFormatter();
            NetworkStream ns = new NetworkStream(socket);
            try
            {
                Int32 command = 4; //ShowResult
                bf.Serialize(ns, command);
                bf.Serialize(ns, id);
                ns.Flush();
                socket.Shutdown(SocketShutdown.Send);
                Int32 error_code = (Int32)bf.Deserialize(ns);
                if (error_code != 0) throw new Exception("My Custom exception");
                int[] array = (int[])bf.Deserialize(ns);
                return array;
            }
            finally
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Disconnect(false);
            }

        }
        static void Main(string[] args)
        {
            new Program(IPAddress.Loopback,1930).Start();
            Console.WriteLine("Done");
            Console.ReadLine();
        }
    }
}
